package JobManagementUtils;

/*
This file is part of Open Grid Job Management System (OGJMS).

OGJMS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

OGJMS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with OGJMS.  If not, see <http://www.gnu.org/licenses/>.

The entire and newest source code can be found at http://code.google.com/p/ogjms/  
*/

/*
 *  http://www.globus.org/toolkit/docs/4.0/data/rft/RFT_Public_Interfaces.html
 *  
 *  http://www.globus.org/toolkit/docs/4.0/data/rft/developer-index.html
 *  
 *  http://www-unix.globus.org/toolkit/docs/4.0/data/rft/developer-index.html
 */

import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.apache.axis.client.Stub;
import org.globus.axis.message.addressing.EndpointReferenceType;
import org.globus.axis.util.Util;
import org.globus.rft.generated.BaseRequestType;
import org.globus.rft.generated.CreateReliableFileTransferInputType;
import org.globus.rft.generated.CreateReliableFileTransferOutputType;
import org.globus.rft.generated.DeleteOptionsType;
import org.globus.rft.generated.DeleteRequestType;
import org.globus.rft.generated.DeleteType;
import org.globus.rft.generated.GetStatusSet;
import org.globus.rft.generated.GetStatusSetResponse;
import org.globus.rft.generated.RFTOptionsType;
import org.globus.rft.generated.ReliableFileTransferFactoryPortType;
import org.globus.rft.generated.ReliableFileTransferPortType;
import org.globus.rft.generated.Start;
import org.globus.rft.generated.StartOutputType;
import org.globus.rft.generated.TransferRequestType;
import org.globus.rft.generated.TransferStatusType;
import org.globus.rft.generated.TransferStatusTypeEnumeration;
import org.globus.rft.generated.TransferType;
import org.globus.rft.generated.service.ReliableFileTransferFactoryServiceLocator;
import org.globus.rft.generated.service.ReliableFileTransferServiceAddressingLocator;
import org.globus.wsrf.impl.security.authentication.Constants;
import org.globus.wsrf.impl.security.authorization.NoAuthorization;
import org.globus.wsrf.impl.security.authorization.SelfAuthorization;
import org.globus.wsrf.impl.security.descriptor.ClientSecurityDescriptor;

import org.oasis.wsrf.lifetime.SetTerminationTime;
import org.oasis.wsrf.lifetime.SetTerminationTimeResponse;

public class FileManager{

	private static int terminationTime = 0;

	ReliableFileTransferPortType rft;

	private ArrayList<String> fileIn;

	private ArrayList<String> fileOut;

	private String proxyFile = "";
	private String clientFolderURL = "gsiftp://stefan.grid/home/stefan/";
	private String hostFolderURL = "gsiftp://stefan.grid/tmp/";
	private String delegationURL = "https://stefan.grid:8443/wsrf/services/DelegationFactoryService";
	private String reliableTransferServiceURL = "https://stefan.grid:8443/wsrf/services/ReliableFileTransferService";
	private String reliableTransferFactoryServiceURL = "https://stefan.grid:8443/wsrf/services/ReliableFileTransferFactoryService";

	ReliableFileTransferFactoryPortType factoryPort;
	
	ReliableFileTransferServiceAddressingLocator rftLocator=new ReliableFileTransferServiceAddressingLocator();

	static {
		Util.registerTransport();
	}

	public FileManager(String proxyFile, String clientURL,
			String hostFolderURL, String delegationURL,
			String reliableTransferFactoryServiceURL,
			String reliableTransferServiceURL) {
		super();
		
		this.proxyFile = proxyFile;
		this.clientFolderURL = clientURL;
		this.hostFolderURL = hostFolderURL;
		this.reliableTransferFactoryServiceURL = reliableTransferFactoryServiceURL;
		this.reliableTransferServiceURL = reliableTransferServiceURL;
		this.delegationURL = delegationURL;
		this.fileIn = new ArrayList<String>();
		this.fileOut = new ArrayList<String>();

	}

	public FileManager(List<String> fileIn, List<String> fileOut) {
		super();
		this.fileIn = (ArrayList<String>) fileIn;
		this.fileOut = (ArrayList<String>) fileOut;
	}

	public FileManager(List<String> fileIn, List<String> fileOut,
			int terminationTime) {
		super();
		this.fileIn = (ArrayList<String>) fileIn;
		this.fileOut = (ArrayList<String>) fileOut;
		this.terminationTime = terminationTime;
	}

	public TransferType[] convertToTransferArray(List<String> list,
			String sourceFolder, String destinationFolder) {

		TransferType[] transferArray = new TransferType[list.size()];

		for (int i = 0; i < list.size(); i++) {
			transferArray[i] = new TransferType();
			transferArray[i].setSourceUrl(sourceFolder + list.get(i));
			transferArray[i].setDestinationUrl(destinationFolder + list.get(i));
		}
		return transferArray;
	}

	public DeleteType[] convertToDeleteArray(List<String> in, List<String> out,
			String folder) {
		List<String> newList = new ArrayList<String>();
		for (int i = 0; i < in.size(); i++) {
			newList.add(in.get(i));
		}

		for (int i = 0; i < out.size(); i++) {
			newList.add(out.get(i));
		}

		DeleteType[] deleteArray = new DeleteType[newList.size()];
		for (int i = 0; i < newList.size(); i++) {
			deleteArray[i] = new DeleteType();
			deleteArray[i].setFile(folder + newList.get(i));
			DeleteOptionsType deleteOptions=new DeleteOptionsType();
			
			deleteArray[i].setDeleteOptions(deleteOptions);
			
		}
		return deleteArray;

	}

	public FTResults submitTranferInJob() {
		TransferType[] transferArray = convertToTransferArray(fileIn,
				clientFolderURL, hostFolderURL);

		FTResults fileTransferResults = null;

		if (transferArray.length > 0) {
			RFTOptionsType rftOptions = new RFTOptionsType();
			rftOptions.setBinary(false);
			// You can set more options like parallel streams, buffer sizes etc
			// Refer to Public Interface guide of RFT for more details
			TransferRequestType request = new TransferRequestType();
			request.setRftOptions(rftOptions);
			request.setTransfer(transferArray);

			try {
				System.out
						.println("\t Setting credential transfer endpoint...[BEGIN]");
				request.setTransferCredentialEndpoint(Utils	
						.delegateCredential(delegationURL, proxyFile));
				System.out
						.println("\t Setting credential transfer endpoint...[END]");
			} catch (Exception e) {
				e.printStackTrace();
			}
			try {
				System.out.println("\t Init port type...[BEGIN]");
				rft = rftLocator
						.getReliableFileTransferPortTypePort(createRFT(
								reliableTransferFactoryServiceURL,
								request));
				System.out.println("\t Init port type...[END]");
				System.out.println("\t Set Security...[BEGIN]");
				setSecurity((Stub) rft);
				System.out.println("\t Set Security...[END]");

				if (terminationTime > 0) {
					Calendar termTime = Calendar.getInstance();
					termTime.add(Calendar.MINUTE, terminationTime);
					System.out.println("\tSet Termination time: "
							+ terminationTime + " minutes [BEGIN]");

					SetTerminationTime reqTermTime = new SetTerminationTime();
					reqTermTime.setRequestedTerminationTime(termTime);

					SetTerminationTimeResponse termRes = rft
							.setTerminationTime(reqTermTime);
					if (termRes != null) {
						System.out.println("\tSet Termination time: "
								+ terminationTime + " minutes [END]");
					}
				}
				StartOutputType startresp = rft.start(new Start());

				// fileTransferResults = processResults(rft,
				// "Transfer Files Needed by Job", transferArray.length);

			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return fileTransferResults;
	}

	public FTResults submitTranferOutJob() {
		FTResults fileTransferResults = null;

		TransferType[] transferArray = convertToTransferArray(fileOut,
				hostFolderURL, clientFolderURL);

		if (transferArray.length > 0) {
			RFTOptionsType rftOptions = new RFTOptionsType();
			rftOptions.setBinary(false);
			// You can set more options like parallel streams, buffer sizes etc
			// Refer to Public Interface guide of RFT for more details
			TransferRequestType request = new TransferRequestType();
			request.setRftOptions(rftOptions);
			request.setTransfer(transferArray);

			try {
				System.out
						.println("\t Setting credential transfer endpoint...[BEGIN]");
				request.setTransferCredentialEndpoint(Utils
						.delegateCredential(delegationURL, proxyFile));
				System.out
						.println("\t Setting credential transfer endpoint...[END]");
			} catch (Exception e) {
				e.printStackTrace();
			}
			try {
				System.out.println("\t Init port type...[BEGIN]");
				rft = rftLocator.getReliableFileTransferPortTypePort(createRFT(
						reliableTransferFactoryServiceURL, request));
				System.out.println("\t Init port type...[END]");
				System.out.println("\t Set Security...[BEGIN]");
				setSecurity((Stub) rft);
				System.out.println("\t Set Security...[END]");
				if (terminationTime > 0) {
					Calendar termTime = Calendar.getInstance();
					termTime.add(Calendar.MINUTE, terminationTime);
					System.out.println("\tSet Termination time: "
							+ terminationTime + " minutes [BEGIN]");

					SetTerminationTime reqTermTime = new SetTerminationTime();
					reqTermTime.setRequestedTerminationTime(termTime);

					SetTerminationTimeResponse termRes = rft
							.setTerminationTime(reqTermTime);
					if (termRes != null) {
						System.out.println("\tSet Termination time: "
								+ terminationTime + " minutes [END]");
					}
				}
				StartOutputType startresp = rft.start(new Start());

				// fileTransferResults = processResults(rft,
				// "Get files generated by the Job", transferArray.length);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return fileTransferResults;
	}

	public FTResults submitDeleteJob() {
		DeleteType[] deleteArray = convertToDeleteArray(fileIn, fileOut,
				hostFolderURL);
		FTResults fileTransferResults = null;
		if (deleteArray.length > 0) {

			DeleteOptionsType deleteOptions = new DeleteOptionsType();
			
			//deleteOptions.setUserName(username);
			
			DeleteRequestType request = new DeleteRequestType();
			request.setDeletion(deleteArray);
			request.setDeleteOptions(deleteOptions);
			

			try {
				System.out
						.println("\t Setting credential transfer endpoint...[BEGIN]");
				request.setTransferCredentialEndpoint(Utils
						.delegateCredential(delegationURL, proxyFile));
				System.out
						.println("\t Setting credential transfer endpoint...[END]");
			} catch (Exception e) {
				e.printStackTrace();
			}
			try {
				System.out.println("\t Init port type...[BEGIN]");
				
				rft = rftLocator.getReliableFileTransferPortTypePort(createRFT(
						reliableTransferFactoryServiceURL, request));

				System.out.println("\t Init port type...[END]");
				System.out.println("\t Set Security...[BEGIN]");
				setSecurity((Stub) rft);
				System.out.println("\t Set Security...[END]");

				if (terminationTime > 0) {
					Calendar termTime = Calendar.getInstance();
					termTime.add(Calendar.MINUTE, terminationTime);
					System.out.println("\tSet Termination time: "
							+ terminationTime + " minutes [BEGIN]");

					SetTerminationTime reqTermTime = new SetTerminationTime();
					reqTermTime.setRequestedTerminationTime(termTime);

					SetTerminationTimeResponse termRes = rft
							.setTerminationTime(reqTermTime);
					if (termRes != null) {
						System.out.println("\tSet Termination time: "
								+ terminationTime + " minutes [END]");
					}
				}
				StartOutputType startresp = rft.start(new Start());

				// fileTransferResults = processResults(
				// "Cleanup any files remaining from the job",
				// deleteArray.length);

			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return fileTransferResults;
	}

	public static EndpointReferenceType createRFT(String rftFactoryAddress,
			BaseRequestType request) throws Exception {
		System.out.println("\t Create Reliable Transfer EPR...[BEGIN]");
		System.out.println("\t\t Get end point...[BEGIN]");
		URL endpoint = new URL(rftFactoryAddress);
		System.out.println("\t\t Get end point...[END]");
		System.out.println("\t\t Get factory port...[BEGIN]");
		ReliableFileTransferFactoryServiceLocator rftFactoryLocator=new ReliableFileTransferFactoryServiceLocator();
		ReliableFileTransferFactoryPortType factoryPort = rftFactoryLocator
				.getReliableFileTransferFactoryPortTypePort(endpoint);

		System.out.println("\t\t Get factory port...[END]");
		System.out
				.println("\t\t Create Reliable File Transfer Input type...[BEGIN]");
		CreateReliableFileTransferInputType input = new CreateReliableFileTransferInputType();
		System.out
				.println("\t\t Create Reliable File Transfer Input type...[END]");

		// input.setTransferJob(transferType);
		System.out.println("\t\t Set Transfer Type...[BEGIN]");
		if (request instanceof TransferRequestType) {
			input.setTransferRequest((TransferRequestType) request);
		} 
		if (request instanceof DeleteRequestType){
			input.setDeleteRequest((DeleteRequestType) request);
		}

		System.out.println("\t\t Set Transfer Type...[END]");

		System.out.println("\t\t Set Termination Time...[BEGIN]");
		Calendar termTime = Calendar.getInstance();
		termTime.add(Calendar.HOUR, 1);
		input.setInitialTerminationTime(termTime);
		System.out.println("\t\t Set Termination Time...[END]");

		System.out.println("\t\t Set Security...[BEGIN]");

		setSecurity((Stub) factoryPort);
		//((Stub)factoryPort)._setProperty(Constants.AUTHORIZATION,SelfAuthorization.getInstance());

		System.out.println("\t\t Set Security...[END]");

		System.out.println("\t\t Create response...[BEGIN]");
		CreateReliableFileTransferOutputType response = factoryPort
				.createReliableFileTransfer(input);
		System.out.println("\t\t Create response...[END]");
		System.out.println("\t Create Reliable Transfer EPR...[END]");
		return response.getReliableTransferEPR();
	}

	// public static void setSecurity(Stub stub) {
	// stub._setProperty(Constants.GSI_SEC_CONV, Constants.SIGNATURE);
	// stub._setProperty(Constants.AUTHORIZATION,
	// new HostAuthorization("host"));
	// }
	//	
	public static void setSecurity(Stub stub) {
		ClientSecurityDescriptor desc = new ClientSecurityDescriptor();
		desc.setAuthz(NoAuthorization.getInstance());
		desc.setGSISecureConv(Constants.SIGNATURE);
		((Stub) stub)._setProperty(Constants.CLIENT_DESCRIPTOR,
				desc);
		
	}

	public FTResults processResults(String operationType,
			int sizeOfTheTransferArray) {

		GetStatusSetResponse resp;

		FTResults fileTransferResults = new FTResults(sizeOfTheTransferArray,
				operationType);
		if (rft != null) {
			try {

				resp = rft.getStatusSet(new GetStatusSet(0,
						sizeOfTheTransferArray));

				TransferStatusType[] type = resp.getTransferStatusSet();

				for (int j = 0; j < type.length; j++) {

					// System.out.println("Status for file "
					// + type[j].getSourceUrl() + "is "
					// + type[j].getStatus());
					if (!type[j].getStatus().equals(
							TransferStatusTypeEnumeration.Failed)
							&& !type[j].getStatus().equals(
									TransferStatusTypeEnumeration.Finished)
							&& !type[j].getStatus().equals(
									TransferStatusTypeEnumeration.Cancelled)) {
						fileTransferResults.setPending(true);
					} else {
						fileTransferResults.setPending(false);
					}

				}
				resp = rft.getStatusSet(new GetStatusSet(0,
						sizeOfTheTransferArray));

				for (int j = 0; j < type.length; j++) {
					if (type[j].getStatus().equals(
							TransferStatusTypeEnumeration.Failed)) {
						fileTransferResults.FTFailed(type[j].getSourceUrl());
					}
					if (type[j].getStatus().equals(
							TransferStatusTypeEnumeration.Finished)) {
						fileTransferResults.FTSucceded(type[j].getSourceUrl());
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return fileTransferResults;
	}

	public int getFileInSize() {
		return fileIn.size();
	}

	public int getFileOutSize() {
		return fileOut.size();
	}

	public void setFileIn(ArrayList<String> fileIn) {
		this.fileIn = fileIn;
	}

	public void setFileOut(ArrayList<String> fileOut) {
		this.fileOut = fileOut;
	}

}
